package qiniu.voidcepc.voicepc.demos.web.utils;


import com.alibaba.nls.client.protocol.InputFormatEnum;
import com.alibaba.nls.client.protocol.NlsClient;
import com.alibaba.nls.client.protocol.SampleRateEnum;
import com.alibaba.nls.client.protocol.asr.SpeechRecognizer;
import com.alibaba.nls.client.protocol.asr.SpeechRecognizerListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;

import java.io.File;
import java.io.FileInputStream;

/**
 * 音频文件读取工具
 * */
@Service
public class VoicePOJO {
    @Autowired
    private NlsClient nlsClient;

    @Autowired
    SpeechRecognizerListenerFactory speechRecognizerListenerFactory;

    @Value("${aliyun.AppKey}")
    private String appKey;//AppKey

    @Value("${voice.sampleBytes}")
    private int sampleBytes;

    @Value("${voice.soundChannel}")
    private int soundChannel;

    private int sampleRate = 16000;

    private String recognizerresult;

    //根据二进制数据大小计算对应的同等语音长度
    //sampleRate仅支持8000或16000。
    public static int getSleepDelta(int dataSize, int sampleRate) {
        return (dataSize * 10 * 8000) / (160 * sampleRate);
    }

    /**
     * 进行本地语音文件的识别
     * */
    public void process(String filepath, int sampleRate) {
        SpeechRecognizer recognizer = null;
        try {
            //传递用户自定义参数
            String myParam = "user-param";
            int myOrder = 1234;
            SpeechRecognizerListener listener = speechRecognizerListenerFactory.getRecognizerListener(myOrder, myParam);
            recognizer = new SpeechRecognizer(nlsClient, listener);
            recognizerSet(recognizer,sampleRate);
            //此方法将以上参数设置序列化为JSON发送给服务端，并等待服务端确认。
            recognizer.start();
            File file = new File(filepath);
            FileInputStream fis = new FileInputStream(file);
            byte[] b = new byte[32000];
            int len;
            while ((len = fis.read(b)) > 0) {
                recognizer.send(b, len);
                //本案例用读取本地文件的形式模拟实时获取语音流，因为读取速度较快，这里需要设置sleep时长。
                // 如果实时获取语音则无需设置sleep时长，如果是8k采样率语音第二个参数设置为8000。
                //int deltaSleep = getSleepDelta(len, sampleRate);
                //Thread.sleep(deltaSleep);
            }

            recognizer.stop();
            recognizerresult = speechRecognizerListenerFactory.getRecognizerResponseText();

            fis.close();
        } catch (Exception e) {
            System.err.println(e.getMessage());
        } finally {
            //关闭连接
            if (null != recognizer) {
                recognizer.close();
            }
        }
    }
    
    /**
     * 自动检测并调整WAV文件采样率，然后进行语音识别
     * @param filepath 语音文件路径
     * @param targetSampleRate 目标采样率（8000或16000）
     * @throws Exception 文件处理或语音识别异常
     */
    public void processWithAutoResample(String filepath, int targetSampleRate) throws Exception {
        // 检查文件是否存在
        File file = new File(filepath);
        if (!file.exists() || !file.isFile()) {
            throw new FileNotFoundException("语音文件不存在: " + filepath);
        }
        
        String processFilePath = filepath;
        boolean needDeleteTempFile = false;
        
        try {
            // 检查文件采样率
            int fileSampleRate = getWavSampleRate(filepath);
            
            // 如果采样率不匹配目标采样率，则进行重采样
            if (fileSampleRate != targetSampleRate) {
                System.out.println("音频文件采样率为" + fileSampleRate + "Hz，目标采样率为" + targetSampleRate + "Hz，进行格式转换...");
                processFilePath = WavReSample.reSampleRate(targetSampleRate, filepath);
                needDeleteTempFile = true;
                System.out.println("采样率转换完成，处理文件: " + processFilePath);
            }
            
            // 处理转换后的文件
            process(processFilePath, targetSampleRate);
        } finally {
            // 如果生成了临时文件，则删除
            if (needDeleteTempFile && !processFilePath.equals(filepath)) {
                File tempFile = new File(processFilePath);
                if (tempFile.exists()) {
                    tempFile.delete();
                    System.out.println("临时文件已删除: " + processFilePath);
                }
            }
        }
    }
    
    /**
     * 自动检测并调整MultipartFile的采样率，然后进行语音识别
     * @param file 语音文件
     * @param targetSampleRate 目标采样率（8000或16000）
     * @throws Exception 文件处理或语音识别异常
     */
    public void processWithAutoResample(MultipartFile file, int targetSampleRate) throws Exception {
        // 创建临时文件
        Path tempFilePath = Files.createTempFile("voice_", ".wav");
        File tempFile = tempFilePath.toFile();
        boolean needDeleteTempFile = true;
        
        try {
            // 保存MultipartFile到临时文件
            file.transferTo(tempFile);
            
            String processFilePath = tempFile.getAbsolutePath();
            boolean needDeleteResampledFile = false;
            
            try {
                // 检查文件采样率
                int fileSampleRate = getWavSampleRate(tempFile.getAbsolutePath());
                
                // 如果采样率不匹配目标采样率，则进行重采样
                if (fileSampleRate != targetSampleRate) {
                    System.out.println("音频文件采样率为" + fileSampleRate + "Hz，目标采样率为" + targetSampleRate + "Hz，进行格式转换...");
                    processFilePath = WavReSample.reSampleRate(targetSampleRate, tempFile.getAbsolutePath());
                    needDeleteResampledFile = true;
                    System.out.println("采样率转换完成，处理文件: " + processFilePath);
                }
                
                // 使用原始process方法处理
                process(processFilePath, targetSampleRate);
            } finally {
                // 清理重采样生成的文件
                if (needDeleteResampledFile && !processFilePath.equals(tempFile.getAbsolutePath())) {
                    File resampledFile = new File(processFilePath);
                    if (resampledFile.exists()) {
                        resampledFile.delete();
                    }
                }
            }
        } finally {
            // 删除原始临时文件
            if (needDeleteTempFile && tempFile.exists()) {
                tempFile.delete();
            }
        }
    }
    
    /**
     * 获取WAV文件的采样率
     * @param filePath WAV文件路径
     * @return 采样率
     * @throws UnsupportedAudioFileException 不支持的音频格式
     * @throws IOException 文件读取异常
     */
    private int getWavSampleRate(String filePath) throws UnsupportedAudioFileException, IOException {
        AudioFileFormat audioFileFormat = AudioSystem.getAudioFileFormat(new File(filePath));
        AudioFormat format = audioFileFormat.getFormat();
        return (int) format.getSampleRate();
    }

    public void process(MultipartFile file, int sampleRate) {
        SpeechRecognizer recognizer = null;
        try {
            //传递用户自定义参数
            String myParam = "user-param";
            int myOrder = 1234;
            SpeechRecognizerListener listener = speechRecognizerListenerFactory.getRecognizerListener(myOrder, myParam);
            recognizer = new SpeechRecognizer(nlsClient, listener);
            recognizerSet(recognizer,sampleRate);
            //此方法将以上参数设置序列化为JSON发送给服务端，并等待服务端确认。
            recognizer.start();

            // 使用MultipartFile的InputStream而不是尝试转换为File
            try (InputStream fis = file.getInputStream()) {
                byte[] b = new byte[3200];
                int len;
                while ((len = fis.read(b)) > 0) {
                    recognizer.send(b, len);
                    //System.out.println(len);
                    //本案例用读取本地文件的形式模拟实时获取语音流，因为读取速度较快，这里需要设置sleep时长。
                    // 如果实时获取语音则无需设置sleep时长，如果是8k采样率语音第二个参数设置为8000。
                    //int deltaSleep = getSleepDelta(len, sampleRate);
                    //Thread.sleep(deltaSleep);
                }
                recognizer.stop();
                recognizerresult = speechRecognizerListenerFactory.getRecognizerResponseText();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // 确保正确关闭recognizer资源
            if (recognizer != null) {
                recognizer.close();
            }
        }
    }
    
    // 辅助方法用于设置Recognizer参数
    private void recognizerSet(SpeechRecognizer recognizer,int sampleRate) {
        if (recognizer != null) {
            recognizer.setAppKey(appKey);
            //设置音频编码格式。如果是OPUS文件，请设置为InputFormatEnum.OPUS。
            recognizer.setFormat(InputFormatEnum.WAV);
            //设置是否返回中间识别结果
            recognizer.setEnableIntermediateResult(true);
           if(sampleRate == 16000) {
               recognizer.setSampleRate(SampleRateEnum.SAMPLE_RATE_16K);
           } else {
               recognizer.setSampleRate(SampleRateEnum.SAMPLE_RATE_8K);
           }
            //设置是否打开语音检测（即vad）
            recognizer.addCustomedParam("enable_voice_detection", true);
        }
    }
    public void shutdown() {
        nlsClient.shutdown();
    }


    public String getRecognizerresult() {
        return recognizerresult;
    }
}
